package cn.com.bsoft.wePortal.partner.support

import cn.com.bsoft.kotlinEx.StatusAndMessageError

import cn.com.bsoft.kotlinEx.sha265
import cn.com.bsoft.wePortal.config.service.ConfigService
import cn.com.bsoft.wePortal.partner.model.PartnerProperties
import cn.com.bsoft.webEx.MutableHttpServletRequest
import org.springframework.http.MediaType
import java.util.*
import javax.servlet.*
import javax.servlet.http.HttpServletRequest

class PartnerFilter(val supportContentTypes:List<MediaType>): Filter {

    companion object {
        const val KeyPartnerFilterTimeStampInterval = "KeyPartnerFilterTimeStampInterval"
        const val DefaultPartnerFilterTimeStampInterval = 10
    }

    lateinit var partnerProperties: PartnerProperties

    lateinit var configService:ConfigService

    override fun destroy() {

    }

    fun checkSign(req:MutableHttpServletRequest):Boolean{
        val now = Date()

        val timeStamp = req.partnerTimeStamp?.toLong()?:throw StatusAndMessageError("读取时间戳错误")

        val ts = Date(timeStamp * 1000)

        val interval = configService.queryValue(KeyPartnerFilterTimeStampInterval,Int::class.java)?:
                DefaultPartnerFilterTimeStampInterval

        val diff = Math.abs(now.time - ts.time)/60/1000

        if (diff > interval)
            throw StatusAndMessageError("时间戳误差过大.误差$diff 分钟 允许误差$interval 分钟")

        val partner = req.partner

        if (true != partner?.enabled)
            throw StatusAndMessageError("Partner ${partner?.code} 被禁用!")

        val bytes = req.out.toByteArray()

        val sha256 = bytes.sha265(
                partner?.secret?.toByteArray(Charsets.UTF_8)
                ,req.partnerTimeStamp?.toByteArray(Charsets.UTF_8))

        if(sha256 == req.partnerSign )
            return true

        return false
    }

    fun isSupportContentType(contentType:MediaType):Boolean{
        return supportContentTypes.any {
            contentType.isCompatibleWith(it)
        }
    }

    override fun doFilter(req: ServletRequest?, resp: ServletResponse?, chain: FilterChain?) {

        val contentTypeStr = req?.contentType?:MediaType.APPLICATION_JSON_UTF8_VALUE

        val contentType = MediaType.parseMediaType(contentTypeStr)

        if (isSupportContentType(contentType)
                && req is HttpServletRequest
                && partnerProperties.keyHttpMethods.contains(req.method)){
            val wrapReq = MutableHttpServletRequest(req)

            if (!checkSign(wrapReq))
                throw StatusAndMessageError("签名错误")

            chain?.doFilter(wrapReq, resp)
        }
        else {
            chain?.doFilter(req, resp)
        }
    }

    override fun init(p0: FilterConfig?) {
        configService.setupVariable(KeyPartnerFilterTimeStampInterval,
                DefaultPartnerFilterTimeStampInterval,
                "Partner Filter 时间戳的最大误差 单位分钟。默认10分钟")
    }

}